package org.hashdb.client.net.nio;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import org.hashdb.client.console.AppConsoleReader;
import org.hashdb.client.manager.NioAppContext;
import org.hashdb.client.net.nio.msg.Message;

import java.util.List;

/**
 * Date: 2024/1/16 21:19
 * 请确保收到的byteBuf完整, 不能出现粘包半包
 *
 * @author huanyuMake-pecdle
 * @version 0.0.1
 */

@ChannelHandler.Sharable
public class CodecDispatcher extends MessageToMessageCodec<ByteBuf, Message<?>> {
    static final byte[] MAGIC = {'h', 'a', 's', 'h'};

    private static final int MAGIC_NUM;

    static {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer().writeBytes(MAGIC);
        MAGIC_NUM = byteBuf.readInt();
        byteBuf.release();
    }

    private final Client client;

    private final AppConsoleReader reader;

    public CodecDispatcher(NioAppContext ctx) {
        this.client = ctx.client();
        this.reader = ctx.reader();
    }

    @Override
    protected void encode(ChannelHandlerContext ctx, Message<?> msg, List<Object> outList) throws Exception {
        reader.messageLn("encode");
        ByteBuf out = client.protocol().codec().encode(ctx, msg);
        reader.messageLn("encode out " + out);
        outList.add(out);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        reader.messageLn("decode");

        // check message
        if (in.readableBytes() < 22 || in.readInt() != MAGIC_NUM) {
            var bytes = new byte[Math.min(in.readableBytes(), 90)];
            in.readBytes(bytes);
            reader.errorLn("illegal message. buf: %s content: '%s'", in, new String(bytes));
            in.release();
            return;
        }
        // check protocol
        var protocol = Protocol.resolve(ctx, in.readByte());
        if (protocol == null) {
            return;
        }
        var message = protocol.codec().decode(ctx, in);
        if (message != null) {
            out.add(message);
        }
        in.release();
        reader.messageLn("decode in " + message);
        //        log.info("MESSAGE PARSE {}", message);
    }
}
